package org.linlinjava.litemall.wx.web;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.notify.NotifyType;
import org.linlinjava.litemall.core.systemConfig.ConfigService;
import org.linlinjava.litemall.core.util.CharUtil;
import org.linlinjava.litemall.core.util.JacksonUtil;
import org.linlinjava.litemall.core.util.RegexUtil;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.core.util.bcrypt.BCryptPasswordEncoder;
import org.linlinjava.litemall.db.domain.LitemallTransferCount;
import org.linlinjava.litemall.db.domain.LitemallUser;
import org.linlinjava.litemall.db.service.LitemallTransferCountService;
import org.linlinjava.litemall.db.service.LitemallUserService;
import org.linlinjava.litemall.db.service.LitemallWalletRecordService;
import org.linlinjava.litemall.wx.annotation.LoginUser;
import org.linlinjava.litemall.wx.dao.UserInfo;
import org.linlinjava.litemall.wx.dao.UserToken;
import org.linlinjava.litemall.wx.dao.WxLoginInfo;
import org.linlinjava.litemall.wx.service.CaptchaCodeManager;
import org.linlinjava.litemall.wx.service.UserTokenManager;
import org.linlinjava.litemall.wx.util.IpUtil;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/wx/auth")
public class WxAuthController {
    private final Log logger = LogFactory.getLog(WxAuthController.class);

    private PlatformTransactionManager txManager;

    private LitemallUserService userService;

    private WxMaService wxService;

    private NotifyService notifyService;

    private LitemallTransferCountService litemallTransferCountService;

    private ConfigService configService;

    private LitemallWalletRecordService walletRecordService;

    public WxAuthController(
        PlatformTransactionManager txManager,
        LitemallUserService userService,
        WxMaService wxService,
        NotifyService notifyService,
        LitemallTransferCountService litemallTransferCountService,
        ConfigService configService,
        LitemallWalletRecordService walletRecordService) {
        this.txManager = txManager;
        this.userService = userService;
        this.wxService = wxService;
        this.notifyService = notifyService;
        this.litemallTransferCountService = litemallTransferCountService;
        this.configService = configService;
        this.walletRecordService = walletRecordService;
    }

    /**
     * 账号登录
     *
     * @param body    请求内容，{ username: xxx, password: xxx }
     * @param request 请求对象
     * @return 登录结果
     * 成功则
     * {
     * errno: 0,
     * errmsg: '成功',
     * data:
     * {
     * token: xxx,
     * tokenExpire: xxx,
     * userInfo: xxx
     * }
     * }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @RequestMapping("login")
    public Object login(@RequestBody String body, HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
        if (username == null || password == null) {
            return ResponseUtil.badArgument();
        }

        List<LitemallUser> userList = userService.queryByUsername(username);
        LitemallUser user = null;
        if (userList.size() > 1) {
            return ResponseUtil.serious();
        } else if (userList.size() == 0) {
            return ResponseUtil.badArgumentValue();
        } else {
            user = userList.get(0);
        }

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(password, user.getPassword())) {
            return ResponseUtil.fail(403, "账号密码不对");
        }

        // userInfo
        UserInfo userInfo = new UserInfo();
        userInfo.setNickName(username);
        userInfo.setAvatarUrl(user.getAvatar());

        // token
        UserToken userToken = UserTokenManager.generateToken(user.getId());

        Map<Object, Object> result = new HashMap<Object, Object>();
        result.put("token", userToken.getToken());
        result.put("tokenExpire", userToken.getExpireTime().toString());
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }

    /**
     * 微信登录
     *
     * @param wxLoginInfo 请求内容，{ code: xxx, userInfo: xxx }
     * @param request     请求对象
     * @return 登录结果
     * 成功则
     * {
     * errno: 0,
     * errmsg: '成功',
     * data:
     * {
     * token: xxx,
     * tokenExpire: xxx,
     * userInfo: xxx
     * }
     * }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @RequestMapping("login_by_weixin")
    public Object loginByWeixin(@RequestBody WxLoginInfo wxLoginInfo, HttpServletRequest request) {
        String code = wxLoginInfo.getCode();
        UserInfo userInfo = wxLoginInfo.getUserInfo();
        if (code == null || userInfo == null) {
            return ResponseUtil.badArgument();
        }

        String sessionKey = null;
        String openId = null;

        try {
            WxMaJscode2SessionResult result = this.wxService.getUserService().getSessionInfo(code);
            sessionKey = result.getSessionKey();
            openId = result.getOpenid();
        }
        catch (me.chanjar.weixin.common.error.WxErrorException wxErrorException) {
            wxErrorException.printStackTrace();
        }

        if (sessionKey == null || openId == null) {
            return ResponseUtil.fail();
        }

        LitemallUser user = userService.queryByOid(openId);
        if (user == null) {
            user = new LitemallUser();
            String randomName = this.generatorUserName();
            user.setUsername(randomName);
            user.setWeixinOpenid(openId);
            user.setAvatar(userInfo.getAvatarUrl());
            user.setNickname(userInfo.getNickName());
            user.setMobile("");
            user.setGender(userInfo.getGender());
            user.setUserLevel((byte)0);
            user.setStatus((byte)0);
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(IpUtil.client(request));
            user.setAddTime(LocalDateTime.now());
            user.setMemberType(false);
            String password = CharUtil.getRandomNum(6);
            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            String encodedPassword = encoder.encode(password);
            user.setPassword(encodedPassword);
            userService.add(user);
            userInfo.setMemberType(false);
        } else {
            if(user.getMemberType()==null){
                userInfo.setMemberType(false);
            }else{
                userInfo.setMemberType(user.getMemberType());
            }
            user.setLastLoginTime(LocalDateTime.now());
            user.setLastLoginIp(IpUtil.client(request));
            userService.update(user);
        }
        String mobile = user.getMobile();
        if (mobile == null || mobile.equals("")) {
            userInfo.setMobile("");
        } else {
            userInfo.setMobile(user.getMobile());
        }
        userInfo.setOpenId(openId);
        userInfo.setId(user.getId());
        // token
        UserToken userToken = UserTokenManager.generateToken(user.getId());

        Map<Object, Object> result = new HashMap<Object, Object>();
        result.put("token", userToken.getToken());
        result.put("tokenExpire", userToken.getExpireTime().toString());
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }

    /**
     * 请求验证码
     *
     * @param body 手机号码{mobile}
     * @return
     */
    @PostMapping("regCaptcha")
    public Object registerCaptcha(@RequestBody String body) {
        String phoneNumber = JacksonUtil.parseString(body, "mobile");
        String code = CharUtil.getRandomNum(6);
        String params = new String("{\"code\":\"" + code + "\"}");

        notifyService.notifySmsTemplateSync(phoneNumber, NotifyType.CAPTCHA, params);
        try {
            Thread.sleep(5000);
        }
        catch (InterruptedException e) {
            e.printStackTrace();
        }
        boolean successful = CaptchaCodeManager.addToCache(phoneNumber, code);
        return successful ? ResponseUtil.ok() : ResponseUtil.badArgument();
    }

    /**
     * 账号注册
     *
     * @param body    请求内容
     *                {
     *                username: xxx,
     *                password: xxx,
     *                mobile: xxx
     *                code: xxx
     *                }
     *                其中code是手机验证码，目前还不支持手机短信验证码
     * @param request 请求对象
     * @return 登录结果
     * 成功则
     * {
     * errno: 0,
     * errmsg: '成功',
     * data:
     * {
     * token: xxx,
     * tokenExpire: xxx,
     * userInfo: xxx
     * }
     * }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("register")
    public Object register(@RequestBody String body, HttpServletRequest request) {
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
        String mobile = JacksonUtil.parseString(body, "mobile");
        String code = JacksonUtil.parseString(body, "code");

        if (username == null || password == null || mobile == null || code == null) {
            return ResponseUtil.badArgument();
        }

        List<LitemallUser> userList = userService.queryByUsername(username);
        if (userList.size() > 0) {
            return ResponseUtil.fail(403, "用户名已注册");
        }

        userList = userService.queryByMobile(mobile);
        if (userList.size() > 0) {
            return ResponseUtil.fail(403, "手机号已注册");
        }
        if (!RegexUtil.isMobileExact(mobile)) {
            return ResponseUtil.fail(403, "手机号格式不正确");
        }
        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return ResponseUtil.fail(403, "验证码错误");
        }

        LitemallUser user = new LitemallUser();

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(password);
        user.setPassword(encodedPassword);

        user = new LitemallUser();
        user.setUsername(username);
        user.setPassword(encodedPassword);
        user.setMobile(mobile);
        user.setWeixinOpenid("");
        user.setAvatar("https://yanxuan.nosdn.127.net/80841d741d7fa3073e0ae27bf487339f.jpg?imageView&quality=90&thumbnail=64x64");
        user.setNickname(username);
        user.setGender((byte)0);
        user.setUserLevel((byte)0);
        user.setStatus((byte)0);
        user.setLastLoginTime(LocalDateTime.now());
        user.setLastLoginIp(IpUtil.client(request));
        user.setAddTime(LocalDateTime.now());
        userService.add(user);

        // userInfo
        UserInfo userInfo = new UserInfo();
        userInfo.setNickName(username);
        userInfo.setAvatarUrl(user.getAvatar());

        // token
        UserToken userToken = UserTokenManager.generateToken(user.getId());

        Map<Object, Object> result = new HashMap<Object, Object>();
        result.put("token", userToken.getToken());
        result.put("tokenExpire", userToken.getExpireTime().toString());
        result.put("userInfo", userInfo);
        return ResponseUtil.ok(result);
    }

    /**
     * 账号密码重置
     *
     * @param body    请求内容
     *                {
     *                password: xxx,
     *                mobile: xxx
     *                code: xxx
     *                }
     *                其中code是手机验证码，目前还不支持手机短信验证码
     * @param request 请求对象
     * @return 登录结果
     * 成功则 { errno: 0, errmsg: '成功' }
     * 失败则 { errno: XXX, errmsg: XXX }
     */
    @PostMapping("reset")
    public Object reset(@RequestBody String body, HttpServletRequest request) {
        String password = JacksonUtil.parseString(body, "password");
        String mobile = JacksonUtil.parseString(body, "mobile");
        String code = JacksonUtil.parseString(body, "code");

        if (mobile == null || code == null || password == null) {
            return ResponseUtil.badArgument();
        }

        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return ResponseUtil.fail(403, "验证码错误");
        }

        List<LitemallUser> userList = userService.queryByMobile(mobile);
        LitemallUser user = null;
        if (userList.size() > 1) {
            return ResponseUtil.serious();
        } else if (userList.size() == 0) {
            return ResponseUtil.fail(403, "手机号未注册");
        } else {
            user = userList.get(0);
        }

        // TODO 重新生成的密码无法登陆
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encodedPassword = encoder.encode(password);
        user.setPassword(encodedPassword);

        userService.update(user);

        return ResponseUtil.ok();
    }

    /**
     * 用于手动重置系统配置
     * 浏览器输入 http://localhost:8082/wx/auth/resetConfig
     *  即可
     * @return
     */
    @GetMapping("resetConfig")
    public  Object resetConfig(){
        configService.inist1();
        return ResponseUtil.ok("成功");
    }

    @GetMapping("mobileList")
    public  Object mobileList(@LoginUser Integer userId){
        if(userId == null){
            return ResponseUtil.unlogin();
        }
        List<LitemallTransferCount> list = litemallTransferCountService.getList(userId);
        return ResponseUtil.ok(list);
    }
    @PostMapping("transfer")
    public Object transfer( @RequestBody String body, HttpServletRequest request){
        String mobile = JacksonUtil.parseString(body, "mobile");
        String oldMobile = JacksonUtil.parseString(body, "oldMobile");
        String code = JacksonUtil.parseString(body, "code");
        String openId = JacksonUtil.parseString(body, "openId");
        String reson = JacksonUtil.parseString(body, "reson");
        BigDecimal zero = new BigDecimal(0.00);
        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return ResponseUtil.fail(403, "验证码错误");
        }

        //获取新手机号码的账户余额
        LitemallUser litemallUser = userService.findByMobile(mobile);
        //获取旧手机号码的账户余额
        LitemallUser litemallUser1 = userService.findByMobile(oldMobile);
        if(litemallUser!=null) {
            if(litemallUser.getWeixinOpenid() == null || litemallUser.getWeixinOpenid().equals("")){
            //有这个用户
            //新账户的积分
            int newIntegral = litemallUser.getIntegral();
            //新账户的爱币
            BigDecimal newBalance = litemallUser.getBalance();
                //没存款
//                if (litemallUser.getWeixinOpenid() != null) {
                    litemallUser1.setMobile(mobile);
                    litemallUser1.setBalance(newBalance.add(litemallUser1.getBalance()));
                    litemallUser1.setIntegral(newIntegral+litemallUser1.getIntegral());
                    litemallUser1.setWeixinOpenid(openId);
                    litemallUser1.setFirstMechanism(litemallUser.getFirstMechanism());
                    //重绑
                    userService.update(litemallUser1);
                    litemallUser.setDeleted(true);
                    userService.update(litemallUser);
                    walletRecordService.updateUserid(litemallUser1.getId(),litemallUser.getId());
                    //插入绑定记录
                    int userId = litemallUser1.getId();
                    addTransferRecord(zero,oldMobile,mobile,userId,reson);

            }else{
                //有存款
                return ResponseUtil.fail(403,"此用户已存在，请换其他号码");
            }
        }else {
            //没这个用户
            //替换手机号码
            LitemallUser litemallUser2=userService.queryByOid(openId);
            litemallUser2.setMobile(mobile);
            userService.update(litemallUser2);
            //插入绑定记录
            int userId = litemallUser2.getId();
            addTransferRecord(zero,oldMobile,mobile,userId,reson);
        }
        return ResponseUtil.ok();
    }

    public void addTransferRecord(BigDecimal zero,String oldMobile,String mobile,int userId,String reson){
        LitemallTransferCount litemallTransferCount = new LitemallTransferCount();
        litemallTransferCount.setBalanceNum(zero);
        litemallTransferCount.setIntegralNum(0);
        litemallTransferCount.setOldMobile(oldMobile);
        litemallTransferCount.setNewMobile(mobile);
        litemallTransferCount.setUserId(userId);
        litemallTransferCount.setOperateTime(LocalDateTime.now());
        if (reson!=null){
            litemallTransferCount.setReson(reson);
        }
        litemallTransferCountService.add(litemallTransferCount);
    }

    @PostMapping("bindMobile")
    public Object bindMobile(@RequestBody String body, HttpServletRequest request) {
        String mobile = JacksonUtil.parseString(body, "mobile");
        String code = JacksonUtil.parseString(body, "code");
        String openId = JacksonUtil.parseString(body, "openId");
        //判断验证码是否正确
        String cacheCode = CaptchaCodeManager.getCachedCaptcha(mobile);
        if (cacheCode == null || cacheCode.isEmpty() || !cacheCode.equals(code)) {
            return ResponseUtil.fail(403, "验证码错误");
        }
        LitemallUser wxUser = userService.queryByOid(openId);
        if (wxUser == null) {
            return ResponseUtil.fail(-1, "用户不存在");
        }
        List<LitemallUser> userList = userService.queryByMobile(mobile);

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String payPassword = CharUtil.getRandomNum(6);
        String encodedPayPassword = encoder.encode(payPassword);
        // 开启事务管理
        DefaultTransactionDefinition def = new DefaultTransactionDefinition();
        def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
        TransactionStatus status = txManager.getTransaction(def);

        if (userList == null || userList.size() <= 0) {
            wxUser.setMobile(mobile);
            wxUser.setPayPassword(encodedPayPassword);
            userService.update(wxUser);
            String params = new String("{\"username\":\"" + wxUser.getUsername() + "\",\"paypassword\":\"" + payPassword + "\"}");
            notifyService.notifySmsTemplate(wxUser.getMobile(), NotifyType.GIVEPAYPASS, params);
        } else if (userList.size() == 1) {
            try {
                LitemallUser user = userList.get(0);
                user.setWeixinOpenid(openId);
                user.setNickname(wxUser.getNickname());
                user.setAvatar(wxUser.getAvatar());
                user.setBalance(wxUser.getBalance().add(user.getBalance()));
                user.setIntegral(wxUser.getIntegral() + user.getIntegral());
                userService.update(user);
                userService.deleteById(wxUser.getId());
            }
            catch (Exception ex) {
                txManager.rollback(status);
                logger.error("系统内部错误", ex);
                return ResponseUtil.fail(403, "绑定失败");
            }
        }
        txManager.commit(status);
        return ResponseUtil.ok(mobile);
    }

    private String generatorUserName() {
        String randomName = CharUtil.getRandomNum(9);
        int num = userService.countSeletive(randomName, null, null, null, null, null);
        if (num == 0) {
            return randomName;
        } else {
            return this.generatorUserName();
        }
    }
}
